package com.treasure.mall.biz.service.core.pay.impl;

import com.treasure.mall.biz.base.AbstractSearchableCrudService;
import com.treasure.mall.biz.base.SpecificationAndSort;
import com.treasure.mall.biz.dto.BaseSaveDTO;
import com.treasure.mall.biz.dto.BaseSearchDTO;
import com.treasure.mall.biz.dto.condition.RefundBillCondition;
import com.treasure.mall.biz.entity.order.AfterSaleBillPO;
import com.treasure.mall.biz.entity.order.BizOrderPO;
import com.treasure.mall.biz.entity.pay.RefundBillPO;
import com.treasure.mall.biz.entity.pay.RefundBillPO_;
import com.treasure.mall.biz.entity.user.UserPO;
import com.treasure.mall.biz.entity.user.UserPO_;
import com.treasure.mall.biz.repository.pay.RefundBillRepository;
import com.treasure.mall.biz.service.core.pay.RefundBillService;
import com.treasure.mall.zbq.common.Jsr310Utils;
import com.treasure.mall.zbq.common.RandomUtils;
import com.treasure.mall.zbq.common.ienum.order.OrderEnums;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.Predicate;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * @author allan
 * @version 1.0.0
 * @date 2020/6/14
 */
@Service
public class RefundBillServiceImpl extends AbstractSearchableCrudService<RefundBillPO, String> implements RefundBillService {
    private RefundBillRepository refundBillRepository;

    @Autowired
    protected RefundBillServiceImpl(RefundBillRepository repository) {
        super(repository);
        this.refundBillRepository = repository;
    }

    @Override
    protected SpecificationAndSort<RefundBillPO> specificationAndSort(BaseSearchDTO searchDTO) {
        RefundBillCondition condition = (RefundBillCondition) searchDTO;

        Specification<RefundBillPO> specification = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();

            if (!StringUtils.isEmpty(condition.getUserKey())) {
                predicates.add(cb.or(
                        cb.like(root.get(RefundBillPO_.userPO).get(UserPO_.mobile), likeAll(condition.getUserKey())),
                        cb.like(root.get(RefundBillPO_.userPO).get(UserPO_.realName), likeAll(condition.getUserKey()))
                ));
            }

            if (!StringUtils.isEmpty(condition.getBillId())) {
                predicates.add(cb.equal(root.get(RefundBillPO_.id), condition.getBillId()));
            }

            if (!StringUtils.isEmpty(condition.getBeginTime())) {
                LocalDateTime beginTime = Jsr310Utils.DateTime.of(condition.getBeginTime());
                predicates.add(cb.greaterThanOrEqualTo(root.get(RefundBillPO_.createTime), beginTime));
            }
            if (!StringUtils.isEmpty(condition.getEndTime())) {
                LocalDateTime endTime = Jsr310Utils.DateTime.of(condition.getEndTime());
                predicates.add(cb.lessThanOrEqualTo(root.get(RefundBillPO_.createTime), endTime));
            }
            if (!StringUtils.isEmpty(condition.getAfterSaleId())) {
                predicates.add(cb.equal(root.get(RefundBillPO_.afterSaleId), condition.getAfterSaleId()));
            }

            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
        };

        Sort sort = new Sort(Sort.Direction.DESC, "createTime");

        return new SpecificationAndSort<>(specification, sort);
    }

    @Override
    @Transactional
    public RefundBillPO save(BaseSaveDTO saveDTO) {
        return null;
    }

    @Override
    @Transactional
    public RefundBillPO create(AfterSaleBillPO afterSaleBillPO, BigDecimal amount, OrderEnums.RefundType refundType) {
        RefundBillPO refundBillPO = new RefundBillPO();
        refundBillPO.setId(RandomUtils.randomFlowNo());
        refundBillPO.setUserPO(new UserPO(afterSaleBillPO.getUserPO().getUserId()));
        refundBillPO.setAfterSaleId(afterSaleBillPO.getId());
        refundBillPO.setOrderId(afterSaleBillPO.getSubOrderId());
        refundBillPO.setPayType(afterSaleBillPO.getPayType());
        refundBillPO.setRefundType(refundType);
        refundBillPO.setDealType(OrderEnums.DealType.ORDER);
        refundBillPO.setRefundTime(LocalDateTime.now());
        refundBillPO.setAmount(amount);

        return repository.save(refundBillPO);
    }

    @Override
    public RefundBillPO create(BizOrderPO orderPO, BigDecimal amount, OrderEnums.RefundType refundType) {
        RefundBillPO refundBillPO = new RefundBillPO();
        refundBillPO.setId(RandomUtils.randomFlowNo());
        refundBillPO.setUserPO(orderPO.getUserPO());
        refundBillPO.setOrderId(orderPO.getOrderId());
        refundBillPO.setPayType(orderPO.getPayType());
        refundBillPO.setRefundType(refundType);
        refundBillPO.setRefundTime(LocalDateTime.now());
        refundBillPO.setAmount(amount);
        refundBillPO.setDealType(orderPO.getDealType());

        return repository.save(refundBillPO);
    }

    @Override
    public List<RefundBillPO> findByOrder(String subOrderId) {
        return refundBillRepository.findByOrderId(subOrderId);
    }

    @Override
    public RefundBillPO findThirdRefund(String subOrderId) {
        return refundBillRepository.findByOrderIdAndRefundType(subOrderId, OrderEnums.RefundType.ORIGINAL_WAY);
    }

    @Override
    public List<RefundBillPO> findUserRefund(String subOrderId) {
        return refundBillRepository.findByOrderIdAndRefundTypeIsNot(subOrderId, OrderEnums.RefundType.ORIGINAL_WAY);
    }
}
